home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / hash / md5dual.c < prev    next >
Encoding:
Text File  |  1994-03-25  |  13.1 KB  |  523 lines  |  [TEXT/R*ch]

  1. /* @(#)md5dual.c    10.1 3/25/94 08:04:15 */
  2. /*
  3.  * md5dual - md5 dual digest code
  4.  *
  5.  * Split our data into even and odd byte index streams, digest them both
  6.  * and output the digests, space separated on a line with a 0x prefix.
  7.  *
  8.  * This file was written by:
  9.  *
  10.  *     Landon Curt Noll  (chongo@toad.com)    chongo <was here> /\../\
  11.  *
  12.  * This code has been placed in the public domain.  Please do not
  13.  * copyright this code.
  14.  *
  15.  * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH  REGARD  TO
  16.  * THIS  SOFTWARE,  INCLUDING  ALL IMPLIED WARRANTIES OF MER-
  17.  * CHANTABILITY AND FITNESS.  IN NO EVENT SHALL  LANDON  CURT
  18.  * NOLL  BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
  19.  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM  LOSS  OF
  20.  * USE,  DATA  OR  PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  21.  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR  IN
  22.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  23.  *
  24.  * See md5drvr.c for version and modification history.
  25.  */
  26.  
  27. char *MD5dual_what="@(#)";    /* #(@) if checked in */
  28.  
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include "md5.h"
  32.  
  33. /* static declarations */
  34. static void dualData P((BYTE*, UINT, BYTE*, UINT, MD5_CTX*, MD5_CTX*));
  35. static void dualStream P((BYTE*, UINT, FILE*, MD5_CTX*, MD5_CTX*));
  36. static void dualFile P((BYTE*, UINT, char*, MD5_CTX*, MD5_CTX*));
  37. static void dualOutput P((char*, int, MD5_CTX*, MD5_CTX*));
  38.  
  39. /* dual test suite strings */
  40. #define ENTRY(str) {(BYTE *)str, NULL, sizeof(str)-1}
  41. struct dual_test {
  42.     BYTE *ro_data;    /* read only string data or NULL to test */
  43.     BYTE *data;        /* data or NULL to test */
  44.     int len;        /* length of data */
  45. } dual_test_data[] = {
  46.     {NULL, 0},
  47.     ENTRY(""),
  48.     ENTRY("a"),
  49.     ENTRY("aa"),
  50.     ENTRY("aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz"),
  51.     ENTRY("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
  52.     ENTRY("chongo <Ich bin, du bist, aber ein Yit ist nicht!!! :-)> /\\../\\"),
  53.     ENTRY("123456789 123456789 123456789 123456789 123456789 123456789 1234"),
  54.     ENTRY("a123456789 123456789 123456789 123456789 123456789 123456789 1234")
  55. };
  56. #define MAX_DUAL_TEST_DATA (sizeof(dual_test_data)/sizeof(dual_test_data[0]))
  57.  
  58. /* dual test filenames */
  59. char *dual_test_file[] = {
  60.     "file1",
  61.     "file2",
  62.     "md5.data",
  63.     "/dev/null"
  64. };
  65. #define MAX_DUAL_TEST_FILE (sizeof(dual_test_file)/sizeof(dual_test_file[0]))
  66.  
  67. /* where the test files are located by default */
  68. #if !defined(TLIB)
  69. #define TLIB "."
  70. #endif
  71.  
  72.  
  73. /*
  74.  * dualData - divide data into alternating bytes and digest both halves
  75.  */
  76. static void
  77. dualData(pre_str, pre_len, inString, in_len, even, odd)
  78.     BYTE *pre_str;        /* string prefix or NULL */
  79.     UINT pre_len;        /* length of pre_str */
  80.     BYTE *inString;        /* string to digest */
  81.     UINT in_len;        /* length of inString */
  82.     MD5_CTX *even;        /* even byte digest */
  83.     MD5_CTX *odd;        /* odd byte digest */
  84. {
  85.     int len;            /* total length of pre_str and inString */
  86.     BYTE *even_buf;        /* even byte array */
  87.     BYTE *odd_buf;        /* odd byte array */
  88.     int indx;            /* byte stream index */
  89.     BYTE *p;
  90.     int i;
  91.  
  92.     /*
  93.      * determine lengths
  94.      */
  95.     len = (pre_str == NULL) ? 0 : pre_len;
  96.     len += (inString == NULL) ? 0 : in_len;
  97.     /* no strings, quick return */
  98.     if (len == 0) {
  99.         return;
  100.     }
  101.     /* only 1 byte, process now and return */
  102.     if (len == 1) {
  103.         if (pre_str) {
  104.             MD5Update(even, (BYTE *)pre_str, 1);
  105.             COUNT(even, 1);
  106.         } else {
  107.             MD5Update(odd, (BYTE *)inString, 1);
  108.             COUNT(odd, 1);
  109.         }
  110.         return;
  111.     }
  112.  
  113.     /*
  114.      * malloc both string halves
  115.      */
  116.     odd_buf = (BYTE *)malloc(len/2);
  117.     if (odd_buf == NULL) {
  118.     fprintf(stderr, "%s: bad malloc #1\n", program);
  119.     exit(51);
  120.     }
  121.     even_buf = (BYTE *)malloc((len+1)/2);
  122.     if (even_buf == NULL) {
  123.     fprintf(stderr, "%s: bad malloc #2\n", program);
  124.     exit(52);
  125.     }
  126.  
  127.     /*
  128.      * divide the pre-string
  129.      */
  130.     indx = 0;
  131.     if (pre_str != NULL) {
  132.     for (p=pre_str, i=0; i < pre_len; ++indx, ++i, ++p) {
  133.         if (indx & 0x1) {
  134.             odd_buf[indx>>1] = *p;
  135.         } else {
  136.             even_buf[indx>>1] = *p;
  137.         }
  138.     }
  139.     }
  140.  
  141.     /*
  142.      * divide the string
  143.      */
  144.     if (inString != NULL) {
  145.     for (p=inString, i=0; i < in_len; ++indx, ++i, ++p) {
  146.         if (indx & 0x1) {
  147.             odd_buf[indx>>1] = *p;
  148.         } else {
  149.             even_buf[indx>>1] = *p;
  150.         }
  151.     }
  152.     }
  153.  
  154.     /*
  155.      * update both halves
  156.      */
  157.     MD5Update(even, even_buf, (len+1)/2);
  158.     COUNT(even, (len+1)/2);
  159.     MD5Update(odd, odd_buf, len/2);
  160.     COUNT(odd, len/2);
  161.  
  162.     /*
  163.      * cleanup
  164.      */
  165.     free(even_buf);
  166.     free(odd_buf);
  167. }
  168.  
  169.  
  170. /*
  171.  * dualStream - divide a Stream into alternating bytes and digest both halves
  172.  */
  173. static void
  174. dualStream(pre_str, pre_len, stream, even, odd)
  175.     BYTE *pre_str;        /* data prefix or NULL */
  176.     UINT pre_len;        /* length of pre_str */
  177.     FILE *stream;        /* the stream to process */
  178.     MD5_CTX *even;        /* even byte digest */
  179.     MD5_CTX *odd;        /* odd byte digest */
  180. {
  181.     BYTE data[2*READSIZE];    /* our read buffer */
  182.     BYTE even_buf[READSIZE];    /* even half */
  183.     BYTE odd_buf[READSIZE];    /* off half */
  184.     int bytes;            /* bytes last read */
  185.     int epartial;        /* 1 => even partial chunk */
  186.     int opartial;        /* 1 => odd partial chunk */
  187.     int elen;            /* length of even_buf */
  188.     int olen;            /* length of odd_buf */
  189.     BYTE *p;
  190.     int i;
  191.  
  192.     /*
  193.      * pre-process prefix if needed
  194.      */
  195.     if (pre_str != NULL) {
  196.     dualData(pre_str, pre_len, NULL, 0, even, odd);
  197.     }
  198.  
  199.     /*
  200.      * determine if either half has a partial chunk
  201.      */
  202.     if (even->datalen > 0) {
  203.     epartial = 1;
  204.     } else {
  205.     epartial = 0;
  206.     }
  207.     if (odd->datalen > 0) {
  208.     opartial = 1;
  209.     } else {
  210.     opartial = 0;
  211.     }
  212.  
  213.     /*
  214.      * process the contents of the file
  215.      */
  216.     while ((bytes = fread((char *)data, 1, READSIZE*2, stream)) > 0) {
  217.  
  218.         /*
  219.          * split bytes into two halves
  220.          */
  221.     for (i=0, olen=0, p=(BYTE *)data; i < bytes-1; i+=2, ++olen, p+=2) {
  222.         even_buf[olen] = *p;
  223.         odd_buf[olen] = *(p+1);
  224.     }
  225.     if (bytes & 0x1) {
  226.         even_buf[olen] = data[bytes-1];
  227.         elen = olen+1;
  228.     } else {
  229.         elen = olen;
  230.     }
  231.  
  232.     /*
  233.      * digest even bytes
  234.      */
  235.     if (epartial) {
  236.         if (even->datalen == 0 && (elen&(MD5_CHUNKSIZE-1)) == 0) {
  237.         MD5fullUpdate(even, even_buf, elen);
  238.         epartial = 0;
  239.         } else {
  240.         MD5Update(even, even_buf, elen);
  241.         }
  242.     } else if ((elen&(MD5_CHUNKSIZE-1)) == 0) {
  243.         MD5fullUpdate(even, even_buf, elen);
  244.     } else {
  245.         MD5Update(even, even_buf, elen);
  246.         epartial = 1;
  247.     }
  248.     COUNT(even, elen);
  249.  
  250.     /*
  251.      * digest odd bytes
  252.      */
  253.     if (opartial) {
  254.         if (odd->datalen == 0 && (olen&(MD5_CHUNKSIZE-1)) == 0) {
  255.         MD5fullUpdate(odd, odd_buf, olen);
  256.         opartial = 0;
  257.         } else {
  258.         MD5Update(odd, odd_buf, olen);
  259.         }
  260.     } else if ((olen&(MD5_CHUNKSIZE-1)) == 0) {
  261.         MD5fullUpdate(odd, odd_buf, olen);
  262.     } else {
  263.         MD5Update(odd, odd_buf, olen);
  264.         opartial = 1;
  265.     }
  266.     COUNT(odd, olen);
  267.     }
  268. }
  269.  
  270.  
  271. /*
  272.  * dualFile - divide a file into alternating bytes and digest both halves
  273.  */
  274. static void
  275. dualFile(pre_str, pre_len, filename, even, odd)
  276.     BYTE *pre_str;        /* string prefix or NULL */
  277.     UINT pre_len;        /* length of pre_str */
  278.     char *filename;        /* the filename to process */
  279.     MD5_CTX *even;        /* even byte digest */
  280.     MD5_CTX *odd;        /* odd byte digest */
  281. {
  282.     FILE *inFile;        /* the open file stream */
  283.     struct stat buf;        /* stat or lstat of file */
  284.     struct hashstat hashbuf;    /* stat data to digest */
  285.     struct hashstat hashlbuf;    /* lstat data to digest */
  286.  
  287.     /*
  288.      * open the file
  289.      */
  290.     inFile = fopen(filename, "rb");
  291.     if (inFile == NULL) {
  292.     fprintf(stderr, "%s: cannot open %s: ", program, filename);
  293.     perror("");
  294.     return;
  295.     }
  296.  
  297.     /*
  298.      * pre-process prefix if needed
  299.      */
  300.     if (pre_str == NULL) {
  301.     if (i_flag) {
  302.         dualData(NULL, 0, (BYTE *)filename, strlen(filename), even, odd);
  303.     }
  304.     } else {
  305.     if (i_flag) {
  306.         dualData(pre_str, pre_len, (BYTE *)filename, strlen(filename),
  307.              even, odd);
  308.     } else {
  309.         dualData(pre_str, pre_len, NULL, 0, even, odd);
  310.     }
  311.     }
  312.  
  313.     /*
  314.      * digest file stat and lstat
  315.      */
  316.     if (i_flag) {
  317.     if (fstat(fileno(inFile), &buf) < 0) {
  318.         printf("%s can't be stated.\n", filename);
  319.         return;
  320.     }
  321.     hashbuf.st_dev = buf.st_dev;
  322.     hashbuf.st_ino = buf.st_ino;
  323.     hashbuf.st_mode = buf.st_mode;
  324.     hashbuf.st_nlink = buf.st_nlink;
  325.     hashbuf.st_uid = buf.st_uid;
  326.     hashbuf.st_gid = buf.st_gid;
  327.     hashbuf.st_size = buf.st_size;
  328.     hashbuf.st_mtime = buf.st_mtime;
  329.     hashbuf.st_ctime = buf.st_ctime;
  330.     if (lstat(filename, &buf) < 0) {
  331.         printf("%s can't be lstated.\n", filename);
  332.         return;
  333.     }
  334.     hashlbuf.st_dev = buf.st_dev;
  335.     hashlbuf.st_ino = buf.st_ino;
  336.     hashlbuf.st_mode = buf.st_mode;
  337.     hashlbuf.st_nlink = buf.st_nlink;
  338.     hashlbuf.st_uid = buf.st_uid;
  339.     hashlbuf.st_gid = buf.st_gid;
  340.     hashlbuf.st_size = buf.st_size;
  341.     hashlbuf.st_mtime = buf.st_mtime;
  342.     hashlbuf.st_ctime = buf.st_ctime;
  343.         dualData((BYTE *)&hashbuf, sizeof(hashbuf), (BYTE *)&hashlbuf,
  344.              sizeof(hashlbuf), even, odd);
  345.  
  346.     /*
  347.      * pad both halves with zeros to process file data faster
  348.      */
  349.     if (even->datalen > 0) {
  350.         MD5Update(even, (BYTE *)zero, MD5_CHUNKSIZE - even->datalen);
  351.         COUNT(even, MD5_CHUNKSIZE - even->datalen);
  352.     }
  353.     if (odd->datalen > 0) {
  354.         MD5Update(odd, (BYTE *)zero, MD5_CHUNKSIZE - odd->datalen);
  355.         COUNT(odd, MD5_CHUNKSIZE - odd->datalen);
  356.     }
  357.     }
  358.  
  359.     /*
  360.      * process the data stream
  361.      */
  362.     dualStream(NULL, 0, inFile, even, odd);
  363.     fclose(inFile);
  364. }
  365.  
  366.  
  367. /*
  368.  * dualOutput - output the dual digests
  369.  */
  370. static void
  371. dualOutput(str, quot, even, odd)
  372.     char *str;        /* print string after digest, NULL => none */
  373.     int quot;        /* 1 => surround str with a double quotes */
  374.     MD5_CTX *even;    /* even byte digest */
  375.     MD5_CTX *odd;    /* odd byte digest */
  376. {
  377.     /*
  378.      * finalize both sets
  379.      */
  380.     MD5Final(even);
  381.     MD5Final(odd);
  382.  
  383.     /*
  384.      * print the 320 bit hex value
  385.      */
  386.     MD5Print(even);
  387.     putchar(' ');
  388.     MD5Print(odd);
  389.     if (str && !q_flag) {
  390.     if (quot) {
  391.         printf(" \"%s\"\n", str);
  392.     } else {
  393.         printf(" %s\n", str);
  394.     }
  395.     } else {
  396.     putchar('\n');
  397.     }
  398. }
  399.  
  400.  
  401. /*
  402.  * dualTest - MD5 dual test suite
  403.  */
  404. void
  405. dualTest()
  406. {
  407.     struct dual_test *t;    /* current dual test */
  408.     struct dual_test *p;    /* current dual pre-string test */
  409.     struct stat buf;        /* stat of a test file */
  410.     MD5_CTX even_dig;        /* even byte digest */
  411.     MD5_CTX odd_dig;        /* odd byte digest */
  412.     char **f;            /* current file being tested */
  413.     int i;
  414.     int j;
  415.  
  416.     /*
  417.      * copy our test strings into writable data
  418.      */
  419.     for (i=0, t=dual_test_data; i < MAX_DUAL_TEST_DATA; ++i, ++t) {
  420.     if (t->ro_data != NULL) {
  421.         t->data = (BYTE *)malloc(t->len + 1);
  422.         if (t->data == NULL) {
  423.         fprintf(stderr, "%s: malloc #5 failed\n", program);
  424.         exit(53);
  425.         }
  426.         strcpy((char *)t->data, (char *)t->ro_data);
  427.         }
  428.     }
  429.  
  430.     /*
  431.      * find all of the test files
  432.      */
  433.     for (i=0, f=dual_test_file; i < MAX_DUAL_TEST_FILE; ++i, ++f) {
  434.     if (stat(*f, &buf) < 0) {
  435.         /* no file1 in this directory, cd to the test suite directory */
  436.         if (chdir(TLIB) < 0) {
  437.         fflush(stdout);
  438.         fprintf(stderr,
  439.             "%s: cannot find %s or %s/%s\n", program, *f, TLIB, *f);
  440.         return;
  441.         }
  442.     }
  443.     }
  444.  
  445.     /*
  446.      * try all combinations of test strings as prefixes and data
  447.      */
  448.     for (i=0, t=dual_test_data; i < MAX_DUAL_TEST_DATA; ++i, ++t) {
  449.     for (j=0, p=dual_test_data; j < MAX_DUAL_TEST_DATA; ++j, ++p) {
  450.         printf("pre:%d data:%d\n", i, j);
  451.         MD5Init(&even_dig);
  452.         MD5Init(&odd_dig);
  453.         dualData(p->data, p->len, t->data, t->len, &even_dig, &odd_dig);
  454.         dualOutput(NULL, 0, &even_dig, &odd_dig);
  455.     }
  456.     }
  457.  
  458.     /*
  459.      * try the files with all test strings as prefixes
  460.      */
  461.     for (i=0, p=dual_test_data; i < MAX_DUAL_TEST_DATA; ++i, ++p) {
  462.     for (j=0, f=dual_test_file; j < MAX_DUAL_TEST_FILE; ++j, ++f) {
  463.         printf("pre:%d file:%s\n", i, *f);
  464.         MD5Init(&even_dig);
  465.         MD5Init(&odd_dig);
  466.         dualFile(p->data, p->len, *f, &even_dig, &odd_dig);
  467.         dualOutput(NULL, 0, &even_dig, &odd_dig);
  468.     }
  469.     }
  470.     exit(0);
  471. }
  472.  
  473.  
  474. /*
  475.  * dualMain - main driver of MD5 dual routines
  476.  */
  477. void
  478. dualMain(argc, argv, pre_str, pre_len, data_str)
  479.     int argc;            /* arg count left after getopt */
  480.     char **argv;        /* args left after getopt */
  481.     BYTE *pre_str;        /* pre-process this data first */
  482.     UINT pre_len;        /* length of pre_str */
  483.     char *data_str;        /* data is this string, not a file */
  484. {
  485.     extern int optind;        /* option index */
  486.     MD5_CTX even_dig;        /* even byte digest */
  487.     MD5_CTX odd_dig;        /* odd byte digest */
  488.  
  489.     /*
  490.      * case: initialize both halves
  491.      */
  492.     MD5Init(&even_dig);
  493.     MD5Init(&odd_dig);
  494.  
  495.     /*
  496.      * digest a string
  497.      */
  498.     if (data_str != NULL) {
  499.     dualData(pre_str, pre_len, (BYTE *)data_str, strlen(data_str),
  500.         &even_dig, &odd_dig);
  501.     dualOutput(data_str, 1, &even_dig, &odd_dig);
  502.  
  503.     /*
  504.      * case: digest stdin
  505.      */
  506.     } else if (optind == argc) {
  507.     dualStream(pre_str, pre_len, stdin, &even_dig, &odd_dig);
  508.     dualOutput(NULL, 0, &even_dig, &odd_dig);
  509.  
  510.     /*
  511.      * case: digest files
  512.      */
  513.     } else {
  514.     if (i_flag) {
  515.         dot_zero = 1;
  516.     }
  517.     for (; optind < argc; optind++) {
  518.         dualFile(pre_str, pre_len, argv[optind], &even_dig, &odd_dig);
  519.         dualOutput(argv[optind], 0, &even_dig, &odd_dig);
  520.     }
  521.     }
  522. }
  523.